import java.util.function.Supplier;

public class LazyInitializationExample {
    // 存储已初始化的对象
    private HeavyObject heavyObject;

    // 提供对象的Supplier
    private final Supplier<HeavyObject> heavyObjectSupplier = () -> new HeavyObject();

    // 延迟获取对象
    public HeavyObject getHeavyObject() {
        if (heavyObject == null) {
            // 下面两种实例化,耗时一样
            /*为什么用 Supplier？
            不是为了性能（性能无区别），而是为了代码组织：
            - 将创建逻辑封装在 `Supplier` 中，使 `getHeavyObject()` 更简洁
            - 便于替换创建策略（例如测试时用 `Supplier` 提供模拟对象）
            - 与 Java 函数式编程范式一致*/
            heavyObject = heavyObjectSupplier.get(); // 仅在首次调用时初始化
            //heavyObject = new HeavyObject(); // 耗时操作
        }
        return heavyObject;
    }

    // 模拟重量级对象
    static class HeavyObject {
        public HeavyObject() {
            // 模拟耗时初始化过程
            System.out.println("HeavyObject initialized (simulating expensive operation)");
            try {
                Thread.sleep(1000); // 模拟耗时
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {  // HeavyObject 作为静态内部类不会在类加载时自动实例化。
        LazyInitializationExample example = new LazyInitializationExample();

        long s_1 = System.currentTimeMillis();
        // 首次调用时初始化
        System.out.println("First call:");
        example.getHeavyObject();
        long s_2 = System.currentTimeMillis();
        System.out.println("Time taken: " + (s_2 - s_1) + "ms");

        // 后续调用直接返回已初始化对象
        System.out.println("\nSecond call (no initialization):");
        example.getHeavyObject();
        long s_3 = System.currentTimeMillis();
        System.out.println("Time taken: " + (s_3 - s_2) + "ms");
    }
}
